Module 3: Analysing results produce from Modules 1 and 2

library(png)

Consolidate available files into a single table

# A frequent scenario in our analysis code is that we need to read thousands of 
# output files into a single table. 
# There are a couple flavors of file name that need to be dealt with and the 
# output file needs to include a column with the full file name for reference 
# later. We want to save the final table as it's own file to a folder outside of 
# the one we just read. 

## Here is one flaver where the input is two folders, one with extant 
# simulations and one with extinct simulations. Need to read the files and 
# produce two tables, one for extinct and one for extant. 

## First consolidate the available files into a single table
concatenate <- function(path) {
 available <- list.files(path, full.names = TRUE)
 name <- unlist(strsplit(available[1], split="_"))
 n <- length(available)
 n_name <- length(name) - 1
 load(available[1])
 ncol_files <- length(Sim_statistics[[1]]) + n_name
 files <- matrix(nrow = n,
                 ncol = ncol_files)
 split_names <- function(x){unlist(strsplit(x, split = "_"))}
 name_available <- do.call(rbind, lapply(as.list(available), split_names))
 files[, 1:n_name] <- name_available[, -ncol(name_available)]

 for (i in 1:n) {
   error <- try(load(available[i]), silent = TRUE)
   if (class(error) != "try-error") {
     files[i, (n_name + 1):ncol_files] <- Sim_statistics[[1]]
   }
 }


 files <- files[, -c(1, 2, 3, 5, 7, 8, 13, 18, 23, 28, 33, 35)]
 last_name <- colnames(Sim_statistics[[1]])
 if (is.null(last_name)) {

   files <- files[, -ncol(files)]
 }
 colnames(files) <-  c("Sim_stats_rep", "combo", paste0("P.speciation", 1:4),
                       paste0("P.extinct", 1:4),  paste0("P.diffus", 1:4),
                       paste0("P.TO", 1:4),  paste0("P.Arisal", 1:4), 
                       "timesteps", "NBS", last_name)

 Concatenated_data <- as.data.frame(files)

 begin <- which(colnames(Concatenated_data) ==  "number_of_branches")
 Concatenated_data_stat <- Concatenated_data[, begin:ncol(Concatenated_data)]
 Concatenated_data_stat <- apply(Concatenated_data_stat, 2, as.numeric)
 remove <- which(is.na(rowSums(Concatenated_data_stat)))
 Concatenated_data <- Concatenated_data[-remove, ]

 one <- subset(Concatenated_data, combo =="01")
 two <- subset(Concatenated_data, combo =="02")
 five <- subset(Concatenated_data, combo =="05")
 six <- subset(Concatenated_data, combo =="06")

 crop <- min(sapply(list(one, two, five, six), nrow))

 one <- one[1:crop, ]
 two <- two[1:crop, ]
 five <- five[1:crop, ]
 six <- six[1:crop, ]

 Concatenated_data2 <- rbind(one, two, five, six)
 res <- list(Concatenated_data, Concatenated_data2, crop)
 names(res) <- c("Concatenated_data", "Concatenated_data_crop", "crop")
 return(res)
 
}

path <- "~/Box Sync/Four model compare third run/Module 2"
Concatenated_data0 <- concatenate(path)
print(Concatenated_data0[[3]])
path_save <- "~/Box Sync/Four model compare third run"
Concatenated_data <- Concatenated_data0[[1]]
save(Concatenated_data, file = paste0(path_save,
                                     "/Four_model_compare_results_not_cropped.Rdata"))
Concatenated_data <- Concatenated_data0[[2]]
save(Concatenated_data, file=paste0(path_save,
                                   "/Four_model_compare_results_", 
                                   format(Sys.time(), format="%d_%b_%Y"),
                                   "_crop_to_", Concatenated_data0[[3]],".Rdata"))

### Repeated for extinct
path <- "~/Box Sync/Four model compare third run/Module 2 extinct"
Concatenated_data <- concatenate(path)[[1]]
path_save <- "~/Box Sync/Four model compare third run"

save(Concatenated_data, file=paste0(path_save,
                                   "/Four_model_compare_results_extinct_", 
                                   format(Sys.time(), format="%d_%b_%Y"),".Rdata"))

Summarize overall extinction rates

load("Four_model_compare_results_02_Aug_2017_crop_to_6128.Rdata")
extant <- Concatenated_data
extant

 load("Four_model_compare_results_extinct_02_Aug_2017.Rdata")
extinct <- Concatenated_data
extinct

head(extant)
head(extinct)
for(i in c(3:22)){
    extinct[which(is.nan(as.numeric(as.character(extinct[, i]))) == TRUE), i] <- NA
}

for(i in c(3:22)){
    extant[which(is.nan(as.numeric(as.character(extant[, i]))) == TRUE), i] <- NA
}




xlimit <- c(0,1)
ylimit <- c(0,3000)
maincex <- 0.9

png(file="Global_success_rate_per_parameter.png", width=8.5, height=11, units="in", res=300)

par(mfrow=c(5,4), mar=c(3,3,3,0))


hist(as.numeric(as.character(extinct[,3])), main="speciation of F in F env", col=adjustcolor("firebrick", alpha=0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,3])), main="speciation of F in F env", col=adjustcolor("cornflowerblue", alpha=0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


hist(as.numeric(as.character(extinct[,4])), main="speciation of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,4])), main="speciation of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


hist(as.numeric(as.character(extinct[,5])), main="speciation of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,5])), main="speciation of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[,6])), main="speciation of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[,6])), main="speciation of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

#######

hist(as.numeric(as.character(extinct[, 7])), main="extinction of F in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 7])), main="extinction of F in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


hist(as.numeric(as.character(extinct[, 8])), main="extinction of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 8])), main="extinction of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 9])), main="extinction of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 9])), main="extinction of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 10])), main="extinction of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 10])), main="extinction of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

######

hist(as.numeric(as.character(extinct[, 11])), main="arisal of F in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 11])), main="arisal of F in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 12])), main="arisal of D in F env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 12])), main="arisal of D in F env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 13])), main="arisal of F in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 13])), main="arisal of F in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 14])), main="arisal of D in D env", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 14])), main="arisal of D in D env", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

######

hist(as.numeric(as.character(extinct[, 15])), main="NOPE -- Diffusion: source F, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex)
hist(as.numeric(as.character(extant[, 15])), main="NOPE -- Diffusion: source F, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 16])), main="Diffusion: source D, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 16])), main="Diffusion: source D, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 17])), main="Diffusion: source F, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 17])), main="Diffusion: source F, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 18])), main="NOPE -- Diffusion: source D, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex)
hist(as.numeric(as.character(extant[, 18])), main="NOPE -- Diffusion: source D, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= c(0,18000), cex.main= maincex, add=TRUE)

####

hist(as.numeric(as.character(extinct[, 19])), main="Takeover: source F, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 19])), main="Takeover: source F, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)



hist(as.numeric(as.character(extinct[, 20])), main="Takeover: source D, target F", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 20])), main="Takeover: source D, target F", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 21])), main="Takeover: source F, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 21])), main="Takeover: source F, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)

hist(as.numeric(as.character(extinct[, 22])), main="Takeover: source D, target D", col=adjustcolor("firebrick", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex)
hist(as.numeric(as.character(extant[, 22])), main="Takeover: source D, target D", col=adjustcolor("cornflowerblue", alpha= 0.7), breaks=100, border=NA, xlim= xlimit, ylim= ylimit, cex.main= maincex, add=TRUE)


dev.off()

Run a single random forest on available outputs

# Packages
library(randomForest)

# Radom Forest Function
RF <- function(table_sim, table_real, ntree = 2000, stats_remove = NULL,
              repetitions = 100) {
 # table_sim = table croped 

 begin <- which(colnames(table_sim) ==  "number_of_branches")
 table_sim_data <- table_sim[, begin:ncol(table_sim)]
 table_sim_data <- apply(table_sim_data, 2, as.numeric)
 if (any(is.infinite(table_sim_data))) {
   stop("There is infinite values in the simulation statistics")
 }
 rf_data <- data.frame("Model" = table_sim$combo, table_sim_data)
 rf_data_real <- data.frame(table_real)

 if (!is.null(stats_remove)) {
   rf_data <- rf_data[, -stats_remove]
   rf_data_real <- rf_data_real[, -stats_remove]
 }

 fun <- function(x, y, per = .33) {
   sample(which(y$Model == x), round(table(y$Model)[1]*per))
 }

 results <- matrix(nrow = repetitions, ncol = length(table_real) * 6 + 21)
 for (i in 1:repetitions) {
   sub.test <- unlist(lapply(as.list(paste0(0, c(1,2,5,6))), fun,
                             y = rf_data))
   test2 <- rf_data[sub.test, 2:ncol(rf_data)]
   test1 <- rf_data[sub.test, 1]
   train <- rf_data[-sub.test, ]

   fit <- randomForest(Model ~ ., data = train, xtest = test2, 
                       ytest = test1, importance = TRUE, 
                       ntree = ntree, keep.forest = TRUE,
                       replace = TRUE)
  #dev.new()
  #plot(fit)
   predictions <- predict(fit, rf_data_real, type = "prob")
   var_import <- importance(fit)

   error <- mean(fit$test$confusion[, 5])
   confusion <- as.numeric(fit$test$confusion[, 1:4])
   names(confusion) <- paste0("Confusion_", 
                              rep(colnames(fit$test$confusion[, 1:4]),
                                  each = 4),
                              rownames(fit$test$confusion[, 1:4]))
   predictions_prob <- as.numeric(predictions)
   names(predictions_prob) <- paste0("Prediction_prob", colnames(predictions))
   var_import_vec <- as.numeric(var_import)
   names(var_import_vec) <- paste0("var_imp_", 
                                   rep(colnames(var_import), 
                                       each = nrow(var_import)),
                                   "_",
                                   rownames(var_import))
   vec <- c(error, confusion, predictions_prob, var_import_vec)
   results[i, ] <- vec
 }
 colnames(results) <- names(vec)
 colnames(results)[1] <- "Error_test"
 results <- cbind(1:nrow(results), results)
 colnames(results)[1] <- "Replicate"
 return(results)
}

# Multiple Random Forest
RF_mult <- function(table_sim, table_real_mult, ntree = 2000, 
                   stats_remove = NULL, repetitions = 100) {
 n_r <- nrow(table_real_mult)
 n <- repetitions * n_r
 n_col <- ncol(table_real_mult) * 6 + 22
 results <- matrix(nrow = n, ncol = n_col)
 x <- 0
 for (i in seq(1, n, repetitions)) {
   x <- x + 1
   temp <- RF(table_sim, 
              table_real_mult[x, , drop = FALSE],
              ntree = ntree, 
              repetitions = repetitions, 
              stats_remove = stats_remove)
   results[i:(i + repetitions - 1), ] <- temp
 }
 tree <- rep(1:n_r, each = repetitions)
 results <- cbind(tree, results)
 colnames(results) <- c("Tree", colnames(temp))
 return(results)
}

# Accumulation function
RF_acum <- function(table_sim, table_real_mult, ntree = 2000, 
                   stats_remove = NULL, repetitions = 100,
                   resolution = 100, minimun = 100) {
 sequence <- seq(minimun, nrow(table_sim), resolution)
 n_col <- ncol(table_real_mult) * 6 + 24 
 n_r <- nrow(table_real_mult)
 n_seq <- length(sequence)
 n <- repetitions * n_r * n_seq
 results <- matrix(nrow = n, ncol = n_col)
 lottery1 <- which(table_sim$combo == "01")
 lottery2 <- which(table_sim$combo == "02")
 lottery5 <- which(table_sim$combo == "05")
 lottery6 <- which(table_sim$combo == "06")
 sub1 <- sample(lottery1, sequence[1]/4, replace = FALSE)
 sub2 <- sample(lottery2, sequence[1]/4, replace = FALSE)
 sub5 <- sample(lottery5, sequence[1]/4, replace = FALSE)
 sub6 <- sample(lottery6, sequence[1]/4, replace = FALSE)
 for (i in 1:n_seq) {
   if (i != 1) {
     sub1 <- c(sub1, sample(lottery1[-sub1], sequence[1]/4, replace = FALSE))
     sub2 <- c(sub2, sample(lottery2[-sub2], sequence[1]/4, replace = FALSE))
     sub5 <- c(sub5, sample(lottery5[-sub5], sequence[1]/4, replace = FALSE))
     sub6 <- c(sub6, sample(lottery6[-sub6], sequence[1]/4, replace = FALSE))
   }
   temp <- RF_mult(table_sim[c(sub1, sub2, sub5, sub6), ], table_real_mult,
                   ntree = ntree, repetitions = repetitions,
                   stats_remove = stats_remove)
   n_temp <- nrow(temp)
   results[1:n_temp + (n_temp * (i - 1)), ] <- cbind(rep(sequence[i],
                                                         n_temp), temp)
 }
 colnames(results) <- c("Subsample_size", colnames(temp))
 return(results)
}

# TEST FINAL (RUN ONLY THIS)
# Load data
setwd("~/Desktop/RF after bruno")
load("Four model compare third runFour_model_compare_results_28_Jul_2017_crop_to_5767.Rdata")
load("real.analysis_mult.RData")

table_sim = Concatenated_data
table_real = real.analysis.mult[[1]][[1]]
table_real_mult = do.call(rbind, lapply(real.analysis.mult, 
                                       function(x){x[[1]]}))

#start time
time_start <- Sys.time()

# Change the parameters as you wish
res_acum <- RF_acum(table_sim, table_real_mult[100:110,,drop=FALSE], ntree = 2000, 
                   stats_remove = NULL, repetitions = 1,
                   resolution = 5000, minimun = 1000)
                   
#stop time
time_stop <- Sys.time()
difftime(time_stop, time_start)                   

save(res_acum, file="~/Desktop/10_more_tree_out.Rdata")

# Change argument FUN to sd to obtain the standard deviation
plot(aggregate(x = res_acum[, 4], by = list((res_acum[, 1])), FUN = mean), type = "n", ylim=c(0,1))

lines(aggregate(x = res_acum[, 21], by = list((res_acum[, 1])), FUN = mean), type = "l", col="orange")
lines(aggregate(x = res_acum[, 22], by = list((res_acum[, 1])), FUN = mean), type = "l", col="blue")
lines(aggregate(x = res_acum[, 23], by = list((res_acum[, 1])), FUN = mean), type = "l", col="pink")
lines(aggregate(x = res_acum[, 24], by = list((res_acum[, 1])), FUN = mean), type = "l", col="darkgreen")

Visualize outputs from Random Forest analysis

# load outputs from RF runs
load("/Users/Ty/Desktop/small_RF_out.Rdata")
a <- res_acum

load("/Users/Ty/Desktop/10_more_tree_out.Rdata")
b <- res_acum

load("/Users/Ty/Desktop/10_tree_out.Rdata")
c <- res_acum

#object called res_acum
res_acum <- rbind(b,c)
png("overall_error_per_sample_size.png", width = 11, height = 8.5, res = 300, units = "in")
plot(aggregate(x = res_acum[, 4], by = list((res_acum[, 1])), FUN = mean), type="l", ylim=c(0,0.5), ylab="overall confusion error", xlab="sample size")
dev.off()
null device 
          1 
png("predictions.png", width = 11, height = 8.5, res = 300, units = "in")
par(mar=c(5,6,2,1))
# Change argument FUN to sd to obtain the standard deviation
plot(aggregate(x = res_acum[, 4], by = list((res_acum[, 1])), FUN = mean), type = "n", ylim=c(0,1), ylab="probability that our known cultural phylogeny came \n from each type of simulated mechanism", xlab="number of simulation replicates", cex.axis=1.5, cex.lab=1.5)
basic_mean <- aggregate(x = res_acum[, 21], by = list((res_acum[, 1])), FUN = mean)
diffusion_mean <- aggregate(x = res_acum[, 22], by = list((res_acum[, 1])), FUN = mean)
TO_mean <- aggregate(x = res_acum[, 23], by = list((res_acum[, 1])), FUN = mean)
both_mean <- aggregate(x = res_acum[, 24], by = list((res_acum[, 1])), FUN = mean)
                   
basic_sd <- aggregate(x = res_acum[, 21], by = list((res_acum[, 1])), FUN = sd)
diffusion_sd <- aggregate(x = res_acum[, 22], by = list((res_acum[, 1])), FUN = sd)
TO_sd <- aggregate(x = res_acum[, 23], by = list((res_acum[, 1])), FUN = sd)
both_sd <- aggregate(x = res_acum[, 24], by = list((res_acum[, 1])), FUN = sd)
polygon(x=c(basic_mean[,1], rev(basic_mean[,1])), y=c(basic_mean[,2] + basic_sd[,2], rev(basic_mean[,2] - basic_sd[,2])), col=adjustcolor("orange", alpha=0.5), border=NA)
polygon(x=c(diffusion_mean[,1], rev(diffusion_mean[,1])), y=c(diffusion_mean[,2] + diffusion_sd[,2], rev(diffusion_mean[,2] - diffusion_sd[,2])), col=adjustcolor("cornflowerblue", alpha=0.5), border=NA)
polygon(x=c(TO_mean[,1], rev(TO_mean[,1])), y=c(TO_mean[,2] + TO_sd[,2], rev(TO_mean[,2] - TO_sd[,2])), col=adjustcolor("pink", alpha=0.5), border=NA)
polygon(x=c(both_mean[,1], rev(both_mean[,1])), y=c(both_mean[,2] + both_sd[,2], rev(both_mean[,2] - both_sd[,2])), col=adjustcolor("darkgreen", alpha=0.5), border=NA)
lines(basic_mean,  col="orange")
lines(diffusion_mean,  col="cornflowerblue")
lines(TO_mean,  col="pink")
lines(both_mean,  col="darkgreen")
labs <- c("Basic", "+Diffusion", "+Takeover", "+Diffusion +Takeover")
legend("topright", legend=labs, col=c("orange", "cornflowerblue", "pink", "darkgreen"), lty=1, cex=1.5, lwd=10)
dev.off()
null device 
          1 
png("last_step_predictions.png", width = 11, height = 8.5, res = 300, units = "in")
par(mar=c(5,6,2,1))
this <- length(basic_mean[,1])

plot(x=c(0,5), y=c(0,1), type="n",  xaxt="n", ylab="probability that our known cultural phylogeny came \n from each type of simulated mechanism", xlab="", xlim=c(0.5,4.5))
polygon(x=c(0.75,0.75,1.25,1.25), y=c(basic_mean[this,2] - basic_sd[this,2], basic_mean[this,2] + basic_sd[this,2], basic_mean[this,2] + basic_sd[this,2], basic_mean[this,2] - basic_sd[this,2]), col = adjustcolor("orange", alpha=0.5), border=NA )
polygon(x=c(1.75,1.75,2.25,2.25), y=c(diffusion_mean[this,2] - diffusion_sd[this,2], diffusion_mean[this,2] + diffusion_sd[this,2], diffusion_mean[this,2] + diffusion_sd[this,2], diffusion_mean[this,2] - diffusion_sd[this,2]), col = adjustcolor("cornflowerblue", alpha=0.5), border=NA)
polygon(x=c(2.75,2.75,3.25,3.25), y=c(TO_mean[this,2] - TO_sd[this,2], TO_mean[this,2] + TO_sd[this,2], TO_mean[this,2] + TO_sd[this,2], TO_mean[this,2] - TO_sd[this,2]), col = adjustcolor("pink", alpha=0.5), border=NA)
polygon(x=c(3.75,3.75,4.25,4.25), y=c(both_mean[this,2] - both_sd[this,2], both_mean[this,2] + both_sd[this,2], both_mean[this,2] + both_sd[this,2], both_mean[this,2] - both_sd[this,2]), col = adjustcolor("darkgreen", alpha=0.5), border=NA)


lines(x=c(0.5, 1.5), c(basic_mean[this,2], basic_mean[this,2]),  col="orange")
lines(x=c(1.5, 2.5), c(diffusion_mean[this,2], diffusion_mean[this,2]),  col="cornflowerblue")
lines(x=c(2.5, 3.5), c(TO_mean[this,2], TO_mean[this,2]),  col="pink")
lines(x=c(3.5, 4.5), c(both_mean[this,2], both_mean[this,2]),  col="darkgreen")

legend("topright", legend=labs, col=c("orange", "cornflowerblue", "pink", "darkgreen"), lty=1, cex=1.5, lwd=10)

dev.off()
#colnames(res_acum)
long <- length(Confusion_0101_mean[,1])
Confusion_sum_01 <- aggregate(x = res_acum[, 5:8], by = list((res_acum[, 1])), FUN = mean)
Confusion_sum_02 <- aggregate(x = res_acum[, 9:12], by = list((res_acum[, 1])), FUN = mean)
Confusion_sum_03 <- aggregate(x = res_acum[, 13:16], by = list((res_acum[, 1])), FUN = mean)
Confusion_sum_04 <- aggregate(x = res_acum[, 17:20], by = list((res_acum[, 1])), FUN = mean)
percent_one <- (Confusion_sum_01[long,2:5]/sum(Confusion_sum_01[long,2:5])) * 100
percent_two <- (Confusion_sum_02[long,2:5]/sum(Confusion_sum_02[long,2:5])) * 100
percent_three <- (Confusion_sum_03[long,2:5]/sum(Confusion_sum_03[long,2:5])) * 100
percent_four <- (Confusion_sum_04[long,2:5]/sum(Confusion_sum_04[long,2:5])) * 100
confusion <- matrix(c(percent_one, percent_two, percent_three, percent_four), 4,4)
labs <- c("Basic", "+Diffusion", "+Takeover", "+Diffusion",  "+Takeover")
colors1 <- colorRampPalette(colors = c("grey95", "grey40"))
png("confusion_matrix.png", width = 8.5, height = 8.5, res = 600, units = "in")
par(mar=c(8,8,1,1))
plot(0,0,xlim=c(-0.2,1.4), ylim=c(-0.2,1.4), xaxt="n", xlab="", yaxt="n", ylab="" , bty="n")
#image(prop, col = colors1(20), axes=FALSE)
axis(1, at=c(0, .4, .8, 1.2, 1.3), labels=labs, tick = FALSE, line = FALSE, cex.axis = 1, pos = -.19, las=2)
axis(2, at=rev(c(-0.05, 0.05, .4, .8, 1.2)), labels=labs, tick = FALSE, line = FALSE, cex.axis = 1, las=2)
mtext("percent of time that RF identifies input model as each model type", side = 1, padj = 10, cex = 1)
mtext("known model type given to random forest", side = 2, padj = -10, cex = 1)
for(i in 1:4) {
  for(j in 4:1) {
    xs <- c(0, .4, .8, 1.2)[i]
    ys <- rev(c(0, .4, .8, 1.2))[j]
    polygon(x=c(xs-0.2, xs-0.2, xs+0.2, xs+0.2), y=c(ys-0.2, ys+0.2, ys+0.2, ys-0.2), col=colors1(100)[round(as.numeric(confusion[i, j]), 1)+1])
    if(i == j){text(x = xs, y = ys, paste0(round(as.numeric(confusion[i, j]), 2), "%"), cex = 2.2, col="limegreen")}else{(text(x = xs, y = ys, paste0(round(as.numeric(confusion[i, j]), 2), "%"), cex = 2.2, col="black"))}
  }
}
importance(fit)
# Variables importance

imp <- importance(fit)
imp <- apply(imp, 2, function(x) (x - min(x))/(max(x) - min(x)))
imp <- imp[sort(imp[, 5], index.return = TRUE, decreasing = TRUE)$ix, ]


names <- rownames(imp)
names[names == "spatial.tests.fora"] <- "Space F"
names[names == "spatial.tests.dom"] <- "Space D"
names[names == "sprate"] <- "Sp(ratio)"
names[names == "transition_from_trait_1_to_2"] <- "TR(1-2)"
names[names == "transition_from_trait_2_to_1"] <- "TR(2-1)"
names[names == "Phylogenetic_signal"] <- "PhySig(D)"
names[names == "Evolutionary_distinctiveness_sum"] <- "EDsum"
names[names == "Pylo_diversity_is_sum_of_BL"] <- "PDsum"
names[names == "transition_rate_ratio_1to2_over_2to1"] <- "TR(ratio)"
names[names == "gamma"] <- "Gamma"
names[names == "mean_Phylogenetic_isolation"] <- "MPI"
names[names == "extrate"] <- "Ext(ratio)"
names[names == "average_phylogenetic_diversity_is_mean_of_BL"] <- "PDmean"
names[names == "extinction_per_speciation"] <- "DR"
names[names == "variance_Phylogenetic_isolation"] <- "VPI"
names[names == "F_quadratic_entropy_is_sum_of_PD"] <- "F"
names[names == "Mean_pairwise_distance"] <- "MPD"
names[names == "variance_Pylo_diversity_is_variance_of_BL"] <- "PDvar"
names[names == "variance_pairwise_distance"] <- "VPD"


png("var_import_all.png", width = 25, height = 25, unit="in", res=300)
par(mar = c(10, 18, 1, 1))
plot(x = rev(imp[, 5]), y = 1:nrow(imp), type = "l", yaxt = "n", 
     ylab = "", xlab = "Variable Importance",
     xlim = c(0, 1), lwd = 2, cex.lab = 4)
for (i in 1:nrow(imp)) {
  abline(h = i, lty = 3, col = "gray80")
}
abline(v = seq(0, 1, 1/19), lty = 3, col = "gray80")

lines(x = rev(imp[, 4]), y = 1:nrow(imp), col = "darkgreen", lwd = 2)
lines(x = rev(imp[, 3]), y = 1:nrow(imp), col = "red", lwd = 2)
lines(x = rev(imp[, 2]), y = 1:nrow(imp), col = "blue", lwd = 2)
lines(x = rev(imp[, 1]), y = 1:nrow(imp), col = "darkorange1", lwd = 2)
lines(x = rev(imp[, 5]), y = 1:nrow(imp), lwd = 3)

points(x = rev(imp[, 4]), y = 1:nrow(imp), col = "darkgreen", cex = 2)
points(x = rev(imp[, 3]), y = 1:nrow(imp), col = "red", cex = 2)
points(x = rev(imp[, 2]), y = 1:nrow(imp), col = "blue", cex = 2)
points(x = rev(imp[, 1]), y = 1:nrow(imp), col = "darkorange1", cex = 2)
points(x = rev(imp[, 5]), y = 1:nrow(imp), pch = 20, cex = 3)


text(y = 1:nrow(imp), x = par("usr")[1] - .17, labels = rev(names),
     srt = 0, pos = 4, xpd = T, cex = 4)
dev.off()
par(mfrow=c(2,3))

# Box plots
boxplot(spatial.tests.fora ~ Model, data = data.analysis.comp3)
abline(h = a$spatial.tests.fora, col = "red", lty = 2)

boxplot(spatial.tests.dom ~ Model, data = data.analysis.comp3)
abline(h = a$spatial.tests.fora, col = "red", lty = 2)

boxplot(log(sprate) ~ Model, data = data.analysis.comp3, ylim = c(-10, 10))
abline(h = log(a$sprate), col = "red", lty = 2)

boxplot(log(extrate) ~ Model, data = data.analysis.comp3, ylim = c(-10, 10))
abline(h = log(a$extrate), col = "red", lty = 2)

boxplot(log(transition_rate_ratio_1to2_over_2to1) ~ Model, data = data.analysis.comp3)
abline(h = log(a$sprate), col = "red", lty = 2)

boxplot(Phylogenetic_signal ~ Model, data = data.analysis.comp3, ylim = c(0, 1))
abline(h = a$Phylogenetic_signal, col = "red", lty = 2)
#build a data tracking table to track parameter changes through time

str(fit)

y
LS0tCnRpdGxlOiAnRC1wbGFjZSBGQVJNIGRvY3VtZW50YXRpb246IE1vZHVsZSAzJwphdXRob3I6ICJUeSBUdWZmLCBCcnVubyBWaWxlbGEsIGFuZCBDYXJsb3MgQm90ZXJvIgpkYXRlOiAncHJvamVjdCBiZWdhbjogMTUgTWF5IDIwMTYsIGRvY3VtZW50IHVwZGF0ZWQ6IGByIHN0cmZ0aW1lKFN5cy50aW1lKCksIGZvcm1hdAogID0gIiVkICVCICVZIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CmJpYmxpb2dyYXBoeTogRkFSTSBwYWNrYWdlLmJpYgotLS0KCiMgTW9kdWxlIDM6IEFuYWx5c2luZyByZXN1bHRzIHByb2R1Y2UgZnJvbSBNb2R1bGVzIDEgYW5kIDIKCmBgYHtyfQpsaWJyYXJ5KHBuZykKYGBgCgoKIyMgQ29uc29saWRhdGUgYXZhaWxhYmxlIGZpbGVzIGludG8gYSBzaW5nbGUgdGFibGUKYGBge3J9CiMgQSBmcmVxdWVudCBzY2VuYXJpbyBpbiBvdXIgYW5hbHlzaXMgY29kZSBpcyB0aGF0IHdlIG5lZWQgdG8gcmVhZCB0aG91c2FuZHMgb2YgCiMgb3V0cHV0IGZpbGVzIGludG8gYSBzaW5nbGUgdGFibGUuIAojIFRoZXJlIGFyZSBhIGNvdXBsZSBmbGF2b3JzIG9mIGZpbGUgbmFtZSB0aGF0IG5lZWQgdG8gYmUgZGVhbHQgd2l0aCBhbmQgdGhlIAojIG91dHB1dCBmaWxlIG5lZWRzIHRvIGluY2x1ZGUgYSBjb2x1bW4gd2l0aCB0aGUgZnVsbCBmaWxlIG5hbWUgZm9yIHJlZmVyZW5jZSAKIyBsYXRlci4gV2Ugd2FudCB0byBzYXZlIHRoZSBmaW5hbCB0YWJsZSBhcyBpdCdzIG93biBmaWxlIHRvIGEgZm9sZGVyIG91dHNpZGUgb2YgCiMgdGhlIG9uZSB3ZSBqdXN0IHJlYWQuIAoKIyMgSGVyZSBpcyBvbmUgZmxhdmVyIHdoZXJlIHRoZSBpbnB1dCBpcyB0d28gZm9sZGVycywgb25lIHdpdGggZXh0YW50IAojIHNpbXVsYXRpb25zIGFuZCBvbmUgd2l0aCBleHRpbmN0IHNpbXVsYXRpb25zLiBOZWVkIHRvIHJlYWQgdGhlIGZpbGVzIGFuZCAKIyBwcm9kdWNlIHR3byB0YWJsZXMsIG9uZSBmb3IgZXh0aW5jdCBhbmQgb25lIGZvciBleHRhbnQuIAoKIyMgRmlyc3QgY29uc29saWRhdGUgdGhlIGF2YWlsYWJsZSBmaWxlcyBpbnRvIGEgc2luZ2xlIHRhYmxlCmNvbmNhdGVuYXRlIDwtIGZ1bmN0aW9uKHBhdGgpIHsKIGF2YWlsYWJsZSA8LSBsaXN0LmZpbGVzKHBhdGgsIGZ1bGwubmFtZXMgPSBUUlVFKQogbmFtZSA8LSB1bmxpc3Qoc3Ryc3BsaXQoYXZhaWxhYmxlWzFdLCBzcGxpdD0iXyIpKQogbiA8LSBsZW5ndGgoYXZhaWxhYmxlKQogbl9uYW1lIDwtIGxlbmd0aChuYW1lKSAtIDEKIGxvYWQoYXZhaWxhYmxlWzFdKQogbmNvbF9maWxlcyA8LSBsZW5ndGgoU2ltX3N0YXRpc3RpY3NbWzFdXSkgKyBuX25hbWUKIGZpbGVzIDwtIG1hdHJpeChucm93ID0gbiwKICAgICAgICAgICAgICAgICBuY29sID0gbmNvbF9maWxlcykKIHNwbGl0X25hbWVzIDwtIGZ1bmN0aW9uKHgpe3VubGlzdChzdHJzcGxpdCh4LCBzcGxpdCA9ICJfIikpfQogbmFtZV9hdmFpbGFibGUgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KGFzLmxpc3QoYXZhaWxhYmxlKSwgc3BsaXRfbmFtZXMpKQogZmlsZXNbLCAxOm5fbmFtZV0gPC0gbmFtZV9hdmFpbGFibGVbLCAtbmNvbChuYW1lX2F2YWlsYWJsZSldCgogZm9yIChpIGluIDE6bikgewogICBlcnJvciA8LSB0cnkobG9hZChhdmFpbGFibGVbaV0pLCBzaWxlbnQgPSBUUlVFKQogICBpZiAoY2xhc3MoZXJyb3IpICE9ICJ0cnktZXJyb3IiKSB7CiAgICAgZmlsZXNbaSwgKG5fbmFtZSArIDEpOm5jb2xfZmlsZXNdIDwtIFNpbV9zdGF0aXN0aWNzW1sxXV0KICAgfQogfQoKCiBmaWxlcyA8LSBmaWxlc1ssIC1jKDEsIDIsIDMsIDUsIDcsIDgsIDEzLCAxOCwgMjMsIDI4LCAzMywgMzUpXQogbGFzdF9uYW1lIDwtIGNvbG5hbWVzKFNpbV9zdGF0aXN0aWNzW1sxXV0pCiBpZiAoaXMubnVsbChsYXN0X25hbWUpKSB7CgogICBmaWxlcyA8LSBmaWxlc1ssIC1uY29sKGZpbGVzKV0KIH0KIGNvbG5hbWVzKGZpbGVzKSA8LSAgYygiU2ltX3N0YXRzX3JlcCIsICJjb21ibyIsIHBhc3RlMCgiUC5zcGVjaWF0aW9uIiwgMTo0KSwKICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIlAuZXh0aW5jdCIsIDE6NCksICBwYXN0ZTAoIlAuZGlmZnVzIiwgMTo0KSwKICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIlAuVE8iLCAxOjQpLCAgcGFzdGUwKCJQLkFyaXNhbCIsIDE6NCksIAogICAgICAgICAgICAgICAgICAgICAgICJ0aW1lc3RlcHMiLCAiTkJTIiwgbGFzdF9uYW1lKQoKIENvbmNhdGVuYXRlZF9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoZmlsZXMpCgogYmVnaW4gPC0gd2hpY2goY29sbmFtZXMoQ29uY2F0ZW5hdGVkX2RhdGEpID09ICAibnVtYmVyX29mX2JyYW5jaGVzIikKIENvbmNhdGVuYXRlZF9kYXRhX3N0YXQgPC0gQ29uY2F0ZW5hdGVkX2RhdGFbLCBiZWdpbjpuY29sKENvbmNhdGVuYXRlZF9kYXRhKV0KIENvbmNhdGVuYXRlZF9kYXRhX3N0YXQgPC0gYXBwbHkoQ29uY2F0ZW5hdGVkX2RhdGFfc3RhdCwgMiwgYXMubnVtZXJpYykKIHJlbW92ZSA8LSB3aGljaChpcy5uYShyb3dTdW1zKENvbmNhdGVuYXRlZF9kYXRhX3N0YXQpKSkKIENvbmNhdGVuYXRlZF9kYXRhIDwtIENvbmNhdGVuYXRlZF9kYXRhWy1yZW1vdmUsIF0KCiBvbmUgPC0gc3Vic2V0KENvbmNhdGVuYXRlZF9kYXRhLCBjb21ibyA9PSIwMSIpCiB0d28gPC0gc3Vic2V0KENvbmNhdGVuYXRlZF9kYXRhLCBjb21ibyA9PSIwMiIpCiBmaXZlIDwtIHN1YnNldChDb25jYXRlbmF0ZWRfZGF0YSwgY29tYm8gPT0iMDUiKQogc2l4IDwtIHN1YnNldChDb25jYXRlbmF0ZWRfZGF0YSwgY29tYm8gPT0iMDYiKQoKIGNyb3AgPC0gbWluKHNhcHBseShsaXN0KG9uZSwgdHdvLCBmaXZlLCBzaXgpLCBucm93KSkKCiBvbmUgPC0gb25lWzE6Y3JvcCwgXQogdHdvIDwtIHR3b1sxOmNyb3AsIF0KIGZpdmUgPC0gZml2ZVsxOmNyb3AsIF0KIHNpeCA8LSBzaXhbMTpjcm9wLCBdCgogQ29uY2F0ZW5hdGVkX2RhdGEyIDwtIHJiaW5kKG9uZSwgdHdvLCBmaXZlLCBzaXgpCiByZXMgPC0gbGlzdChDb25jYXRlbmF0ZWRfZGF0YSwgQ29uY2F0ZW5hdGVkX2RhdGEyLCBjcm9wKQogbmFtZXMocmVzKSA8LSBjKCJDb25jYXRlbmF0ZWRfZGF0YSIsICJDb25jYXRlbmF0ZWRfZGF0YV9jcm9wIiwgImNyb3AiKQogcmV0dXJuKHJlcykKIAp9CgpwYXRoIDwtICJ+L0JveCBTeW5jL0ZvdXIgbW9kZWwgY29tcGFyZSB0aGlyZCBydW4vTW9kdWxlIDIiCkNvbmNhdGVuYXRlZF9kYXRhMCA8LSBjb25jYXRlbmF0ZShwYXRoKQpwcmludChDb25jYXRlbmF0ZWRfZGF0YTBbWzNdXSkKcGF0aF9zYXZlIDwtICJ+L0JveCBTeW5jL0ZvdXIgbW9kZWwgY29tcGFyZSB0aGlyZCBydW4iCkNvbmNhdGVuYXRlZF9kYXRhIDwtIENvbmNhdGVuYXRlZF9kYXRhMFtbMV1dCnNhdmUoQ29uY2F0ZW5hdGVkX2RhdGEsIGZpbGUgPSBwYXN0ZTAocGF0aF9zYXZlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi9Gb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19ub3RfY3JvcHBlZC5SZGF0YSIpKQpDb25jYXRlbmF0ZWRfZGF0YSA8LSBDb25jYXRlbmF0ZWRfZGF0YTBbWzJdXQpzYXZlKENvbmNhdGVuYXRlZF9kYXRhLCBmaWxlPXBhc3RlMChwYXRoX3NhdmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi9Gb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c18iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQoU3lzLnRpbWUoKSwgZm9ybWF0PSIlZF8lYl8lWSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfY3JvcF90b18iLCBDb25jYXRlbmF0ZWRfZGF0YTBbWzNdXSwiLlJkYXRhIikpCgojIyMgUmVwZWF0ZWQgZm9yIGV4dGluY3QKcGF0aCA8LSAifi9Cb3ggU3luYy9Gb3VyIG1vZGVsIGNvbXBhcmUgdGhpcmQgcnVuL01vZHVsZSAyIGV4dGluY3QiCkNvbmNhdGVuYXRlZF9kYXRhIDwtIGNvbmNhdGVuYXRlKHBhdGgpW1sxXV0KcGF0aF9zYXZlIDwtICJ+L0JveCBTeW5jL0ZvdXIgbW9kZWwgY29tcGFyZSB0aGlyZCBydW4iCgpzYXZlKENvbmNhdGVuYXRlZF9kYXRhLCBmaWxlPXBhc3RlMChwYXRoX3NhdmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi9Gb3VyX21vZGVsX2NvbXBhcmVfcmVzdWx0c19leHRpbmN0XyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdChTeXMudGltZSgpLCBmb3JtYXQ9IiVkXyViXyVZIiksIi5SZGF0YSIpKQoKCgoKCmBgYAoKCiMjIFN1bW1hcml6ZSBvdmVyYWxsIGV4dGluY3Rpb24gcmF0ZXMKYGBge3IgZXZhbD1GQUxTRX0KbG9hZCgiRm91cl9tb2RlbF9jb21wYXJlX3Jlc3VsdHNfMDJfQXVnXzIwMTdfY3JvcF90b182MTI4LlJkYXRhIikKZXh0YW50IDwtIENvbmNhdGVuYXRlZF9kYXRhCmV4dGFudAoKIGxvYWQoIkZvdXJfbW9kZWxfY29tcGFyZV9yZXN1bHRzX2V4dGluY3RfMDJfQXVnXzIwMTcuUmRhdGEiKQpleHRpbmN0IDwtIENvbmNhdGVuYXRlZF9kYXRhCmV4dGluY3QKCmhlYWQoZXh0YW50KQpoZWFkKGV4dGluY3QpCmBgYAoKCgoKCgpgYGB7ciBldmFsPUZBTFNFfQoKZm9yKGkgaW4gYygzOjIyKSl7CglleHRpbmN0W3doaWNoKGlzLm5hbihhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgaV0pKSkgPT0gVFJVRSksIGldIDwtIE5BCn0KCmZvcihpIGluIGMoMzoyMikpewoJZXh0YW50W3doaWNoKGlzLm5hbihhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCBpXSkpKSA9PSBUUlVFKSwgaV0gPC0gTkEKfQoKCgoKeGxpbWl0IDwtIGMoMCwxKQp5bGltaXQgPC0gYygwLDMwMDApCm1haW5jZXggPC0gMC45CgpwbmcoZmlsZT0iR2xvYmFsX3N1Y2Nlc3NfcmF0ZV9wZXJfcGFyYW1ldGVyLnBuZyIsIHdpZHRoPTguNSwgaGVpZ2h0PTExLCB1bml0cz0iaW4iLCByZXM9MzAwKQoKcGFyKG1mcm93PWMoNSw0KSwgbWFyPWMoMywzLDMsMCkpCgoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywzXSkpLCBtYWluPSJzcGVjaWF0aW9uIG9mIEYgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPTAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssM10pKSwgbWFpbj0ic3BlY2lhdGlvbiBvZiBGIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPTAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLDRdKSksIG1haW49InNwZWNpYXRpb24gb2YgRCBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssNF0pKSwgbWFpbj0ic3BlY2lhdGlvbiBvZiBEIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0Wyw1XSkpLCBtYWluPSJzcGVjaWF0aW9uIG9mIEYgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLDVdKSksIG1haW49InNwZWNpYXRpb24gb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0Wyw2XSkpLCBtYWluPSJzcGVjaWF0aW9uIG9mIEQgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLDZdKSksIG1haW49InNwZWNpYXRpb24gb2YgRCBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKIyMjIyMjIwoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgN10pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBGIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgN10pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBGIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgOF0pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBEIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgOF0pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBEIGluIEYgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCA5XSkpLCBtYWluPSJleHRpbmN0aW9uIG9mIEYgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCA5XSkpLCBtYWluPSJleHRpbmN0aW9uIG9mIEYgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDEwXSkpLCBtYWluPSJleHRpbmN0aW9uIG9mIEQgaW4gRCBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAxMF0pKSwgbWFpbj0iZXh0aW5jdGlvbiBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjIyMKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDExXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDExXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBGIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAxMl0pKSwgbWFpbj0iYXJpc2FsIG9mIEQgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAxMl0pKSwgbWFpbj0iYXJpc2FsIG9mIEQgaW4gRiBlbnYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDEzXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDEzXSkpLCBtYWluPSJhcmlzYWwgb2YgRiBpbiBEIGVudiIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgMTRdKSksIG1haW49ImFyaXNhbCBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMTRdKSksIG1haW49ImFyaXNhbCBvZiBEIGluIEQgZW52IiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjIyMKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDE1XSkpLCBtYWluPSJOT1BFIC0tIERpZmZ1c2lvbjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IGMoMCwxODAwMCksIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDE1XSkpLCBtYWluPSJOT1BFIC0tIERpZmZ1c2lvbjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0gYygwLDE4MDAwKSwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAxNl0pKSwgbWFpbj0iRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCkKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRhbnRbLCAxNl0pKSwgbWFpbj0iRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDE3XSkpLCBtYWluPSJEaWZmdXNpb246IHNvdXJjZSBGLCB0YXJnZXQgRCIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDE3XSkpLCBtYWluPSJEaWZmdXNpb246IHNvdXJjZSBGLCB0YXJnZXQgRCIsIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgsIGFkZD1UUlVFKQoKaGlzdChhcy5udW1lcmljKGFzLmNoYXJhY3RlcihleHRpbmN0WywgMThdKSksIG1haW49Ik5PUEUgLS0gRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImZpcmVicmljayIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0gYygwLDE4MDAwKSwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMThdKSksIG1haW49Ik5PUEUgLS0gRGlmZnVzaW9uOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSBjKDAsMTgwMDApLCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgojIyMjCgpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGluY3RbLCAxOV0pKSwgbWFpbj0iVGFrZW92ZXI6IHNvdXJjZSBGLCB0YXJnZXQgRiIsIGNvbD1hZGp1c3Rjb2xvcigiZmlyZWJyaWNrIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4KQpoaXN0KGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV4dGFudFssIDE5XSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEYsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhPSAwLjcpLCBicmVha3M9MTAwLCBib3JkZXI9TkEsIHhsaW09IHhsaW1pdCwgeWxpbT0geWxpbWl0LCBjZXgubWFpbj0gbWFpbmNleCwgYWRkPVRSVUUpCgoKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDIwXSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEQsIHRhcmdldCBGIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjBdKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRCwgdGFyZ2V0IEYiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDIxXSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEYsIHRhcmdldCBEIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjFdKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRiwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0aW5jdFssIDIyXSkpLCBtYWluPSJUYWtlb3Zlcjogc291cmNlIEQsIHRhcmdldCBEIiwgY29sPWFkanVzdGNvbG9yKCJmaXJlYnJpY2siLCBhbHBoYT0gMC43KSwgYnJlYWtzPTEwMCwgYm9yZGVyPU5BLCB4bGltPSB4bGltaXQsIHlsaW09IHlsaW1pdCwgY2V4Lm1haW49IG1haW5jZXgpCmhpc3QoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXh0YW50WywgMjJdKSksIG1haW49IlRha2VvdmVyOiBzb3VyY2UgRCwgdGFyZ2V0IEQiLCBjb2w9YWRqdXN0Y29sb3IoImNvcm5mbG93ZXJibHVlIiwgYWxwaGE9IDAuNyksIGJyZWFrcz0xMDAsIGJvcmRlcj1OQSwgeGxpbT0geGxpbWl0LCB5bGltPSB5bGltaXQsIGNleC5tYWluPSBtYWluY2V4LCBhZGQ9VFJVRSkKCgpkZXYub2ZmKCkKCgoKCgoKYGBgCgoKIVtdKEdsb2JhbF9zdWNjZXNzX3JhdGVfcGVyX3BhcmFtZXRlci5wbmcpCgoKCgojIyBSdW4gYSBzaW5nbGUgcmFuZG9tIGZvcmVzdCBvbiBhdmFpbGFibGUgb3V0cHV0cwpgYGB7cn0KIyBQYWNrYWdlcwpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKCiMgUmFkb20gRm9yZXN0IEZ1bmN0aW9uClJGIDwtIGZ1bmN0aW9uKHRhYmxlX3NpbSwgdGFibGVfcmVhbCwgbnRyZWUgPSAyMDAwLCBzdGF0c19yZW1vdmUgPSBOVUxMLAogICAgICAgICAgICAgIHJlcGV0aXRpb25zID0gMTAwKSB7CiAjIHRhYmxlX3NpbSA9IHRhYmxlIGNyb3BlZCAKCiBiZWdpbiA8LSB3aGljaChjb2xuYW1lcyh0YWJsZV9zaW0pID09ICAibnVtYmVyX29mX2JyYW5jaGVzIikKIHRhYmxlX3NpbV9kYXRhIDwtIHRhYmxlX3NpbVssIGJlZ2luOm5jb2wodGFibGVfc2ltKV0KIHRhYmxlX3NpbV9kYXRhIDwtIGFwcGx5KHRhYmxlX3NpbV9kYXRhLCAyLCBhcy5udW1lcmljKQogaWYgKGFueShpcy5pbmZpbml0ZSh0YWJsZV9zaW1fZGF0YSkpKSB7CiAgIHN0b3AoIlRoZXJlIGlzIGluZmluaXRlIHZhbHVlcyBpbiB0aGUgc2ltdWxhdGlvbiBzdGF0aXN0aWNzIikKIH0KIHJmX2RhdGEgPC0gZGF0YS5mcmFtZSgiTW9kZWwiID0gdGFibGVfc2ltJGNvbWJvLCB0YWJsZV9zaW1fZGF0YSkKIHJmX2RhdGFfcmVhbCA8LSBkYXRhLmZyYW1lKHRhYmxlX3JlYWwpCgogaWYgKCFpcy5udWxsKHN0YXRzX3JlbW92ZSkpIHsKICAgcmZfZGF0YSA8LSByZl9kYXRhWywgLXN0YXRzX3JlbW92ZV0KICAgcmZfZGF0YV9yZWFsIDwtIHJmX2RhdGFfcmVhbFssIC1zdGF0c19yZW1vdmVdCiB9CgogZnVuIDwtIGZ1bmN0aW9uKHgsIHksIHBlciA9IC4zMykgewogICBzYW1wbGUod2hpY2goeSRNb2RlbCA9PSB4KSwgcm91bmQodGFibGUoeSRNb2RlbClbMV0qcGVyKSkKIH0KCiByZXN1bHRzIDwtIG1hdHJpeChucm93ID0gcmVwZXRpdGlvbnMsIG5jb2wgPSBsZW5ndGgodGFibGVfcmVhbCkgKiA2ICsgMjEpCiBmb3IgKGkgaW4gMTpyZXBldGl0aW9ucykgewogICBzdWIudGVzdCA8LSB1bmxpc3QobGFwcGx5KGFzLmxpc3QocGFzdGUwKDAsIGMoMSwyLDUsNikpKSwgZnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZl9kYXRhKSkKICAgdGVzdDIgPC0gcmZfZGF0YVtzdWIudGVzdCwgMjpuY29sKHJmX2RhdGEpXQogICB0ZXN0MSA8LSByZl9kYXRhW3N1Yi50ZXN0LCAxXQogICB0cmFpbiA8LSByZl9kYXRhWy1zdWIudGVzdCwgXQoKICAgZml0IDwtIHJhbmRvbUZvcmVzdChNb2RlbCB+IC4sIGRhdGEgPSB0cmFpbiwgeHRlc3QgPSB0ZXN0MiwgCiAgICAgICAgICAgICAgICAgICAgICAgeXRlc3QgPSB0ZXN0MSwgaW1wb3J0YW5jZSA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgIG50cmVlID0gbnRyZWUsIGtlZXAuZm9yZXN0ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gVFJVRSkKICAjZGV2Lm5ldygpCiAgI3Bsb3QoZml0KQogICBwcmVkaWN0aW9ucyA8LSBwcmVkaWN0KGZpdCwgcmZfZGF0YV9yZWFsLCB0eXBlID0gInByb2IiKQogICB2YXJfaW1wb3J0IDwtIGltcG9ydGFuY2UoZml0KQoKICAgZXJyb3IgPC0gbWVhbihmaXQkdGVzdCRjb25mdXNpb25bLCA1XSkKICAgY29uZnVzaW9uIDwtIGFzLm51bWVyaWMoZml0JHRlc3QkY29uZnVzaW9uWywgMTo0XSkKICAgbmFtZXMoY29uZnVzaW9uKSA8LSBwYXN0ZTAoIkNvbmZ1c2lvbl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGNvbG5hbWVzKGZpdCR0ZXN0JGNvbmZ1c2lvblssIDE6NF0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCA9IDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhmaXQkdGVzdCRjb25mdXNpb25bLCAxOjRdKSkKICAgcHJlZGljdGlvbnNfcHJvYiA8LSBhcy5udW1lcmljKHByZWRpY3Rpb25zKQogICBuYW1lcyhwcmVkaWN0aW9uc19wcm9iKSA8LSBwYXN0ZTAoIlByZWRpY3Rpb25fcHJvYiIsIGNvbG5hbWVzKHByZWRpY3Rpb25zKSkKICAgdmFyX2ltcG9ydF92ZWMgPC0gYXMubnVtZXJpYyh2YXJfaW1wb3J0KQogICBuYW1lcyh2YXJfaW1wb3J0X3ZlYykgPC0gcGFzdGUwKCJ2YXJfaW1wXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcChjb2xuYW1lcyh2YXJfaW1wb3J0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVhY2ggPSBucm93KHZhcl9pbXBvcnQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXModmFyX2ltcG9ydCkpCiAgIHZlYyA8LSBjKGVycm9yLCBjb25mdXNpb24sIHByZWRpY3Rpb25zX3Byb2IsIHZhcl9pbXBvcnRfdmVjKQogICByZXN1bHRzW2ksIF0gPC0gdmVjCiB9CiBjb2xuYW1lcyhyZXN1bHRzKSA8LSBuYW1lcyh2ZWMpCiBjb2xuYW1lcyhyZXN1bHRzKVsxXSA8LSAiRXJyb3JfdGVzdCIKIHJlc3VsdHMgPC0gY2JpbmQoMTpucm93KHJlc3VsdHMpLCByZXN1bHRzKQogY29sbmFtZXMocmVzdWx0cylbMV0gPC0gIlJlcGxpY2F0ZSIKIHJldHVybihyZXN1bHRzKQp9CgojIE11bHRpcGxlIFJhbmRvbSBGb3Jlc3QKUkZfbXVsdCA8LSBmdW5jdGlvbih0YWJsZV9zaW0sIHRhYmxlX3JlYWxfbXVsdCwgbnRyZWUgPSAyMDAwLCAKICAgICAgICAgICAgICAgICAgIHN0YXRzX3JlbW92ZSA9IE5VTEwsIHJlcGV0aXRpb25zID0gMTAwKSB7CiBuX3IgPC0gbnJvdyh0YWJsZV9yZWFsX211bHQpCiBuIDwtIHJlcGV0aXRpb25zICogbl9yCiBuX2NvbCA8LSBuY29sKHRhYmxlX3JlYWxfbXVsdCkgKiA2ICsgMjIKIHJlc3VsdHMgPC0gbWF0cml4KG5yb3cgPSBuLCBuY29sID0gbl9jb2wpCiB4IDwtIDAKIGZvciAoaSBpbiBzZXEoMSwgbiwgcmVwZXRpdGlvbnMpKSB7CiAgIHggPC0geCArIDEKICAgdGVtcCA8LSBSRih0YWJsZV9zaW0sIAogICAgICAgICAgICAgIHRhYmxlX3JlYWxfbXVsdFt4LCAsIGRyb3AgPSBGQUxTRV0sCiAgICAgICAgICAgICAgbnRyZWUgPSBudHJlZSwgCiAgICAgICAgICAgICAgcmVwZXRpdGlvbnMgPSByZXBldGl0aW9ucywgCiAgICAgICAgICAgICAgc3RhdHNfcmVtb3ZlID0gc3RhdHNfcmVtb3ZlKQogICByZXN1bHRzW2k6KGkgKyByZXBldGl0aW9ucyAtIDEpLCBdIDwtIHRlbXAKIH0KIHRyZWUgPC0gcmVwKDE6bl9yLCBlYWNoID0gcmVwZXRpdGlvbnMpCiByZXN1bHRzIDwtIGNiaW5kKHRyZWUsIHJlc3VsdHMpCiBjb2xuYW1lcyhyZXN1bHRzKSA8LSBjKCJUcmVlIiwgY29sbmFtZXModGVtcCkpCiByZXR1cm4ocmVzdWx0cykKfQoKIyBBY2N1bXVsYXRpb24gZnVuY3Rpb24KUkZfYWN1bSA8LSBmdW5jdGlvbih0YWJsZV9zaW0sIHRhYmxlX3JlYWxfbXVsdCwgbnRyZWUgPSAyMDAwLCAKICAgICAgICAgICAgICAgICAgIHN0YXRzX3JlbW92ZSA9IE5VTEwsIHJlcGV0aXRpb25zID0gMTAwLAogICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbiA9IDEwMCwgbWluaW11biA9IDEwMCkgewogc2VxdWVuY2UgPC0gc2VxKG1pbmltdW4sIG5yb3codGFibGVfc2ltKSwgcmVzb2x1dGlvbikKIG5fY29sIDwtIG5jb2wodGFibGVfcmVhbF9tdWx0KSAqIDYgKyAyNCAKIG5fciA8LSBucm93KHRhYmxlX3JlYWxfbXVsdCkKIG5fc2VxIDwtIGxlbmd0aChzZXF1ZW5jZSkKIG4gPC0gcmVwZXRpdGlvbnMgKiBuX3IgKiBuX3NlcQogcmVzdWx0cyA8LSBtYXRyaXgobnJvdyA9IG4sIG5jb2wgPSBuX2NvbCkKIGxvdHRlcnkxIDwtIHdoaWNoKHRhYmxlX3NpbSRjb21ibyA9PSAiMDEiKQogbG90dGVyeTIgPC0gd2hpY2godGFibGVfc2ltJGNvbWJvID09ICIwMiIpCiBsb3R0ZXJ5NSA8LSB3aGljaCh0YWJsZV9zaW0kY29tYm8gPT0gIjA1IikKIGxvdHRlcnk2IDwtIHdoaWNoKHRhYmxlX3NpbSRjb21ibyA9PSAiMDYiKQogc3ViMSA8LSBzYW1wbGUobG90dGVyeTEsIHNlcXVlbmNlWzFdLzQsIHJlcGxhY2UgPSBGQUxTRSkKIHN1YjIgPC0gc2FtcGxlKGxvdHRlcnkyLCBzZXF1ZW5jZVsxXS80LCByZXBsYWNlID0gRkFMU0UpCiBzdWI1IDwtIHNhbXBsZShsb3R0ZXJ5NSwgc2VxdWVuY2VbMV0vNCwgcmVwbGFjZSA9IEZBTFNFKQogc3ViNiA8LSBzYW1wbGUobG90dGVyeTYsIHNlcXVlbmNlWzFdLzQsIHJlcGxhY2UgPSBGQUxTRSkKIGZvciAoaSBpbiAxOm5fc2VxKSB7CiAgIGlmIChpICE9IDEpIHsKICAgICBzdWIxIDwtIGMoc3ViMSwgc2FtcGxlKGxvdHRlcnkxWy1zdWIxXSwgc2VxdWVuY2VbMV0vNCwgcmVwbGFjZSA9IEZBTFNFKSkKICAgICBzdWIyIDwtIGMoc3ViMiwgc2FtcGxlKGxvdHRlcnkyWy1zdWIyXSwgc2VxdWVuY2VbMV0vNCwgcmVwbGFjZSA9IEZBTFNFKSkKICAgICBzdWI1IDwtIGMoc3ViNSwgc2FtcGxlKGxvdHRlcnk1Wy1zdWI1XSwgc2VxdWVuY2VbMV0vNCwgcmVwbGFjZSA9IEZBTFNFKSkKICAgICBzdWI2IDwtIGMoc3ViNiwgc2FtcGxlKGxvdHRlcnk2Wy1zdWI2XSwgc2VxdWVuY2VbMV0vNCwgcmVwbGFjZSA9IEZBTFNFKSkKICAgfQogICB0ZW1wIDwtIFJGX211bHQodGFibGVfc2ltW2Moc3ViMSwgc3ViMiwgc3ViNSwgc3ViNiksIF0sIHRhYmxlX3JlYWxfbXVsdCwKICAgICAgICAgICAgICAgICAgIG50cmVlID0gbnRyZWUsIHJlcGV0aXRpb25zID0gcmVwZXRpdGlvbnMsCiAgICAgICAgICAgICAgICAgICBzdGF0c19yZW1vdmUgPSBzdGF0c19yZW1vdmUpCiAgIG5fdGVtcCA8LSBucm93KHRlbXApCiAgIHJlc3VsdHNbMTpuX3RlbXAgKyAobl90ZW1wICogKGkgLSAxKSksIF0gPC0gY2JpbmQocmVwKHNlcXVlbmNlW2ldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3RlbXApLCB0ZW1wKQogfQogY29sbmFtZXMocmVzdWx0cykgPC0gYygiU3Vic2FtcGxlX3NpemUiLCBjb2xuYW1lcyh0ZW1wKSkKIHJldHVybihyZXN1bHRzKQp9CgojIFRFU1QgRklOQUwgKFJVTiBPTkxZIFRISVMpCiMgTG9hZCBkYXRhCnNldHdkKCJ+L0Rlc2t0b3AvUkYgYWZ0ZXIgYnJ1bm8iKQpsb2FkKCJGb3VyIG1vZGVsIGNvbXBhcmUgdGhpcmQgcnVuRm91cl9tb2RlbF9jb21wYXJlX3Jlc3VsdHNfMjhfSnVsXzIwMTdfY3JvcF90b181NzY3LlJkYXRhIikKbG9hZCgicmVhbC5hbmFseXNpc19tdWx0LlJEYXRhIikKCnRhYmxlX3NpbSA9IENvbmNhdGVuYXRlZF9kYXRhCnRhYmxlX3JlYWwgPSByZWFsLmFuYWx5c2lzLm11bHRbWzFdXVtbMV1dCnRhYmxlX3JlYWxfbXVsdCA9IGRvLmNhbGwocmJpbmQsIGxhcHBseShyZWFsLmFuYWx5c2lzLm11bHQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXt4W1sxXV19KSkKCiNzdGFydCB0aW1lCnRpbWVfc3RhcnQgPC0gU3lzLnRpbWUoKQoKIyBDaGFuZ2UgdGhlIHBhcmFtZXRlcnMgYXMgeW91IHdpc2gKcmVzX2FjdW0gPC0gUkZfYWN1bSh0YWJsZV9zaW0sIHRhYmxlX3JlYWxfbXVsdFsxMDA6MTEwLCxkcm9wPUZBTFNFXSwgbnRyZWUgPSAyMDAwLCAKICAgICAgICAgICAgICAgICAgIHN0YXRzX3JlbW92ZSA9IE5VTEwsIHJlcGV0aXRpb25zID0gMSwKICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24gPSA1MDAwLCBtaW5pbXVuID0gMTAwMCkKICAgICAgICAgICAgICAgICAgIAojc3RvcCB0aW1lCnRpbWVfc3RvcCA8LSBTeXMudGltZSgpCmRpZmZ0aW1lKHRpbWVfc3RvcCwgdGltZV9zdGFydCkgICAgICAgICAgICAgICAgICAgCgpzYXZlKHJlc19hY3VtLCBmaWxlPSJ+L0Rlc2t0b3AvMTBfbW9yZV90cmVlX291dC5SZGF0YSIpCgojIENoYW5nZSBhcmd1bWVudCBGVU4gdG8gc2QgdG8gb2J0YWluIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24KcGxvdChhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKSwgdHlwZSA9ICJuIiwgeWxpbT1jKDAsMSkpCgpsaW5lcyhhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgMjFdLCBieSA9IGxpc3QoKHJlc19hY3VtWywgMV0pKSwgRlVOID0gbWVhbiksIHR5cGUgPSAibCIsIGNvbD0ib3JhbmdlIikKbGluZXMoYWdncmVnYXRlKHggPSByZXNfYWN1bVssIDIyXSwgYnkgPSBsaXN0KChyZXNfYWN1bVssIDFdKSksIEZVTiA9IG1lYW4pLCB0eXBlID0gImwiLCBjb2w9ImJsdWUiKQpsaW5lcyhhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgMjNdLCBieSA9IGxpc3QoKHJlc19hY3VtWywgMV0pKSwgRlVOID0gbWVhbiksIHR5cGUgPSAibCIsIGNvbD0icGluayIpCmxpbmVzKGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKSwgdHlwZSA9ICJsIiwgY29sPSJkYXJrZ3JlZW4iKQoKYGBgCgoKIyMgVmlzdWFsaXplIG91dHB1dHMgZnJvbSBSYW5kb20gRm9yZXN0IGFuYWx5c2lzCgpgYGB7ciBldmFsPUZBTFNFfQojIGxvYWQgb3V0cHV0cyBmcm9tIFJGIHJ1bnMKbG9hZCgiL1VzZXJzL1R5L0Rlc2t0b3Avc21hbGxfUkZfb3V0LlJkYXRhIikKYSA8LSByZXNfYWN1bQoKbG9hZCgiL1VzZXJzL1R5L0Rlc2t0b3AvMTBfbW9yZV90cmVlX291dC5SZGF0YSIpCmIgPC0gcmVzX2FjdW0KCmxvYWQoIi9Vc2Vycy9UeS9EZXNrdG9wLzEwX3RyZWVfb3V0LlJkYXRhIikKYyA8LSByZXNfYWN1bQoKI29iamVjdCBjYWxsZWQgcmVzX2FjdW0KcmVzX2FjdW0gPC0gcmJpbmQoYixjKQoKYGBgCgoKYGBge3J9CnBuZygib3ZlcmFsbF9lcnJvcl9wZXJfc2FtcGxlX3NpemUucG5nIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOC41LCByZXMgPSAzMDAsIHVuaXRzID0gImluIikKcGxvdChhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKSwgdHlwZT0ibCIsIHlsaW09YygwLDAuNSksIHlsYWI9Im92ZXJhbGwgY29uZnVzaW9uIGVycm9yIiwgeGxhYj0ic2FtcGxlIHNpemUiKQpkZXYub2ZmKCkKYGBgCiFbXShvdmVyYWxsX2Vycm9yX3Blcl9zYW1wbGVfc2l6ZS5wbmcpCgoKYGBge3J9CgoKcG5nKCJwcmVkaWN0aW9ucy5wbmciLCB3aWR0aCA9IDExLCBoZWlnaHQgPSA4LjUsIHJlcyA9IDMwMCwgdW5pdHMgPSAiaW4iKQpwYXIobWFyPWMoNSw2LDIsMSkpCgojIENoYW5nZSBhcmd1bWVudCBGVU4gdG8gc2QgdG8gb2J0YWluIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24KcGxvdChhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKSwgdHlwZSA9ICJuIiwgeWxpbT1jKDAsMSksIHlsYWI9InByb2JhYmlsaXR5IHRoYXQgb3VyIGtub3duIGN1bHR1cmFsIHBoeWxvZ2VueSBjYW1lIFxuIGZyb20gZWFjaCB0eXBlIG9mIHNpbXVsYXRlZCBtZWNoYW5pc20iLCB4bGFiPSJudW1iZXIgb2Ygc2ltdWxhdGlvbiByZXBsaWNhdGVzIiwgY2V4LmF4aXM9MS41LCBjZXgubGFiPTEuNSkKCgpiYXNpY19tZWFuIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyMV0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQpkaWZmdXNpb25fbWVhbiA8LSBhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgMjJdLCBieSA9IGxpc3QoKHJlc19hY3VtWywgMV0pKSwgRlVOID0gbWVhbikKVE9fbWVhbiA8LSBhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgMjNdLCBieSA9IGxpc3QoKHJlc19hY3VtWywgMV0pKSwgRlVOID0gbWVhbikKYm90aF9tZWFuIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQogICAgICAgICAgICAgICAgICAgCmJhc2ljX3NkIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyMV0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBzZCkKZGlmZnVzaW9uX3NkIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyMl0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBzZCkKVE9fc2QgPC0gYWdncmVnYXRlKHggPSByZXNfYWN1bVssIDIzXSwgYnkgPSBsaXN0KChyZXNfYWN1bVssIDFdKSksIEZVTiA9IHNkKQpib3RoX3NkIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAyNF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBzZCkKCgpwb2x5Z29uKHg9YyhiYXNpY19tZWFuWywxXSwgcmV2KGJhc2ljX21lYW5bLDFdKSksIHk9YyhiYXNpY19tZWFuWywyXSArIGJhc2ljX3NkWywyXSwgcmV2KGJhc2ljX21lYW5bLDJdIC0gYmFzaWNfc2RbLDJdKSksIGNvbD1hZGp1c3Rjb2xvcigib3JhbmdlIiwgYWxwaGE9MC41KSwgYm9yZGVyPU5BKQpwb2x5Z29uKHg9YyhkaWZmdXNpb25fbWVhblssMV0sIHJldihkaWZmdXNpb25fbWVhblssMV0pKSwgeT1jKGRpZmZ1c2lvbl9tZWFuWywyXSArIGRpZmZ1c2lvbl9zZFssMl0sIHJldihkaWZmdXNpb25fbWVhblssMl0gLSBkaWZmdXNpb25fc2RbLDJdKSksIGNvbD1hZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0wLjUpLCBib3JkZXI9TkEpCnBvbHlnb24oeD1jKFRPX21lYW5bLDFdLCByZXYoVE9fbWVhblssMV0pKSwgeT1jKFRPX21lYW5bLDJdICsgVE9fc2RbLDJdLCByZXYoVE9fbWVhblssMl0gLSBUT19zZFssMl0pKSwgY29sPWFkanVzdGNvbG9yKCJwaW5rIiwgYWxwaGE9MC41KSwgYm9yZGVyPU5BKQpwb2x5Z29uKHg9Yyhib3RoX21lYW5bLDFdLCByZXYoYm90aF9tZWFuWywxXSkpLCB5PWMoYm90aF9tZWFuWywyXSArIGJvdGhfc2RbLDJdLCByZXYoYm90aF9tZWFuWywyXSAtIGJvdGhfc2RbLDJdKSksIGNvbD1hZGp1c3Rjb2xvcigiZGFya2dyZWVuIiwgYWxwaGE9MC41KSwgYm9yZGVyPU5BKQoKCgpsaW5lcyhiYXNpY19tZWFuLCAgY29sPSJvcmFuZ2UiKQpsaW5lcyhkaWZmdXNpb25fbWVhbiwgIGNvbD0iY29ybmZsb3dlcmJsdWUiKQpsaW5lcyhUT19tZWFuLCAgY29sPSJwaW5rIikKbGluZXMoYm90aF9tZWFuLCAgY29sPSJkYXJrZ3JlZW4iKQoKbGFicyA8LSBjKCJCYXNpYyIsICIrRGlmZnVzaW9uIiwgIitUYWtlb3ZlciIsICIrRGlmZnVzaW9uICtUYWtlb3ZlciIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9bGFicywgY29sPWMoIm9yYW5nZSIsICJjb3JuZmxvd2VyYmx1ZSIsICJwaW5rIiwgImRhcmtncmVlbiIpLCBsdHk9MSwgY2V4PTEuNSwgbHdkPTEwKQoKZGV2Lm9mZigpCmBgYAohW10ocHJlZGljdGlvbnMucG5nKQoKCgpgYGB7ciBldmFsPUZBTFNFfQoKcG5nKCJsYXN0X3N0ZXBfcHJlZGljdGlvbnMucG5nIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOC41LCByZXMgPSAzMDAsIHVuaXRzID0gImluIikKcGFyKG1hcj1jKDUsNiwyLDEpKQp0aGlzIDwtIGxlbmd0aChiYXNpY19tZWFuWywxXSkKCnBsb3QoeD1jKDAsNSksIHk9YygwLDEpLCB0eXBlPSJuIiwgIHhheHQ9Im4iLCB5bGFiPSJwcm9iYWJpbGl0eSB0aGF0IG91ciBrbm93biBjdWx0dXJhbCBwaHlsb2dlbnkgY2FtZSBcbiBmcm9tIGVhY2ggdHlwZSBvZiBzaW11bGF0ZWQgbWVjaGFuaXNtIiwgeGxhYj0iIiwgeGxpbT1jKDAuNSw0LjUpKQpwb2x5Z29uKHg9YygwLjc1LDAuNzUsMS4yNSwxLjI1KSwgeT1jKGJhc2ljX21lYW5bdGhpcywyXSAtIGJhc2ljX3NkW3RoaXMsMl0sIGJhc2ljX21lYW5bdGhpcywyXSArIGJhc2ljX3NkW3RoaXMsMl0sIGJhc2ljX21lYW5bdGhpcywyXSArIGJhc2ljX3NkW3RoaXMsMl0sIGJhc2ljX21lYW5bdGhpcywyXSAtIGJhc2ljX3NkW3RoaXMsMl0pLCBjb2wgPSBhZGp1c3Rjb2xvcigib3JhbmdlIiwgYWxwaGE9MC41KSwgYm9yZGVyPU5BICkKcG9seWdvbih4PWMoMS43NSwxLjc1LDIuMjUsMi4yNSksIHk9YyhkaWZmdXNpb25fbWVhblt0aGlzLDJdIC0gZGlmZnVzaW9uX3NkW3RoaXMsMl0sIGRpZmZ1c2lvbl9tZWFuW3RoaXMsMl0gKyBkaWZmdXNpb25fc2RbdGhpcywyXSwgZGlmZnVzaW9uX21lYW5bdGhpcywyXSArIGRpZmZ1c2lvbl9zZFt0aGlzLDJdLCBkaWZmdXNpb25fbWVhblt0aGlzLDJdIC0gZGlmZnVzaW9uX3NkW3RoaXMsMl0pLCBjb2wgPSBhZGp1c3Rjb2xvcigiY29ybmZsb3dlcmJsdWUiLCBhbHBoYT0wLjUpLCBib3JkZXI9TkEpCnBvbHlnb24oeD1jKDIuNzUsMi43NSwzLjI1LDMuMjUpLCB5PWMoVE9fbWVhblt0aGlzLDJdIC0gVE9fc2RbdGhpcywyXSwgVE9fbWVhblt0aGlzLDJdICsgVE9fc2RbdGhpcywyXSwgVE9fbWVhblt0aGlzLDJdICsgVE9fc2RbdGhpcywyXSwgVE9fbWVhblt0aGlzLDJdIC0gVE9fc2RbdGhpcywyXSksIGNvbCA9IGFkanVzdGNvbG9yKCJwaW5rIiwgYWxwaGE9MC41KSwgYm9yZGVyPU5BKQpwb2x5Z29uKHg9YygzLjc1LDMuNzUsNC4yNSw0LjI1KSwgeT1jKGJvdGhfbWVhblt0aGlzLDJdIC0gYm90aF9zZFt0aGlzLDJdLCBib3RoX21lYW5bdGhpcywyXSArIGJvdGhfc2RbdGhpcywyXSwgYm90aF9tZWFuW3RoaXMsMl0gKyBib3RoX3NkW3RoaXMsMl0sIGJvdGhfbWVhblt0aGlzLDJdIC0gYm90aF9zZFt0aGlzLDJdKSwgY29sID0gYWRqdXN0Y29sb3IoImRhcmtncmVlbiIsIGFscGhhPTAuNSksIGJvcmRlcj1OQSkKCgpsaW5lcyh4PWMoMC41LCAxLjUpLCBjKGJhc2ljX21lYW5bdGhpcywyXSwgYmFzaWNfbWVhblt0aGlzLDJdKSwgIGNvbD0ib3JhbmdlIikKbGluZXMoeD1jKDEuNSwgMi41KSwgYyhkaWZmdXNpb25fbWVhblt0aGlzLDJdLCBkaWZmdXNpb25fbWVhblt0aGlzLDJdKSwgIGNvbD0iY29ybmZsb3dlcmJsdWUiKQpsaW5lcyh4PWMoMi41LCAzLjUpLCBjKFRPX21lYW5bdGhpcywyXSwgVE9fbWVhblt0aGlzLDJdKSwgIGNvbD0icGluayIpCmxpbmVzKHg9YygzLjUsIDQuNSksIGMoYm90aF9tZWFuW3RoaXMsMl0sIGJvdGhfbWVhblt0aGlzLDJdKSwgIGNvbD0iZGFya2dyZWVuIikKCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9bGFicywgY29sPWMoIm9yYW5nZSIsICJjb3JuZmxvd2VyYmx1ZSIsICJwaW5rIiwgImRhcmtncmVlbiIpLCBsdHk9MSwgY2V4PTEuNSwgbHdkPTEwKQoKZGV2Lm9mZigpCmBgYAohW10obGFzdF9zdGVwX3ByZWRpY3Rpb25zLnBuZykKCgpgYGB7cn0KI2NvbG5hbWVzKHJlc19hY3VtKQoKbG9uZyA8LSBsZW5ndGgoQ29uZnVzaW9uXzAxMDFfbWVhblssMV0pCkNvbmZ1c2lvbl9zdW1fMDEgPC0gYWdncmVnYXRlKHggPSByZXNfYWN1bVssIDU6OF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQpDb25mdXNpb25fc3VtXzAyIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCA5OjEyXSwgYnkgPSBsaXN0KChyZXNfYWN1bVssIDFdKSksIEZVTiA9IG1lYW4pCkNvbmZ1c2lvbl9zdW1fMDMgPC0gYWdncmVnYXRlKHggPSByZXNfYWN1bVssIDEzOjE2XSwgYnkgPSBsaXN0KChyZXNfYWN1bVssIDFdKSksIEZVTiA9IG1lYW4pCkNvbmZ1c2lvbl9zdW1fMDQgPC0gYWdncmVnYXRlKHggPSByZXNfYWN1bVssIDE3OjIwXSwgYnkgPSBsaXN0KChyZXNfYWN1bVssIDFdKSksIEZVTiA9IG1lYW4pCgpwZXJjZW50X29uZSA8LSAoQ29uZnVzaW9uX3N1bV8wMVtsb25nLDI6NV0vc3VtKENvbmZ1c2lvbl9zdW1fMDFbbG9uZywyOjVdKSkgKiAxMDAKcGVyY2VudF90d28gPC0gKENvbmZ1c2lvbl9zdW1fMDJbbG9uZywyOjVdL3N1bShDb25mdXNpb25fc3VtXzAyW2xvbmcsMjo1XSkpICogMTAwCnBlcmNlbnRfdGhyZWUgPC0gKENvbmZ1c2lvbl9zdW1fMDNbbG9uZywyOjVdL3N1bShDb25mdXNpb25fc3VtXzAzW2xvbmcsMjo1XSkpICogMTAwCnBlcmNlbnRfZm91ciA8LSAoQ29uZnVzaW9uX3N1bV8wNFtsb25nLDI6NV0vc3VtKENvbmZ1c2lvbl9zdW1fMDRbbG9uZywyOjVdKSkgKiAxMDAKCgpjb25mdXNpb24gPC0gbWF0cml4KGMocGVyY2VudF9vbmUsIHBlcmNlbnRfdHdvLCBwZXJjZW50X3RocmVlLCBwZXJjZW50X2ZvdXIpLCA0LDQpCgpsYWJzIDwtIGMoIkJhc2ljIiwgIitEaWZmdXNpb24iLCAiK1Rha2VvdmVyIiwgIitEaWZmdXNpb24iLCAgIitUYWtlb3ZlciIpCmNvbG9yczEgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJncmV5OTUiLCAiZ3JleTQwIikpCgoKcG5nKCJjb25mdXNpb25fbWF0cml4LnBuZyIsIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUsIHJlcyA9IDYwMCwgdW5pdHMgPSAiaW4iKQpwYXIobWFyPWMoOCw4LDEsMSkpCnBsb3QoMCwwLHhsaW09YygtMC4yLDEuNCksIHlsaW09YygtMC4yLDEuNCksIHhheHQ9Im4iLCB4bGFiPSIiLCB5YXh0PSJuIiwgeWxhYj0iIiAsIGJ0eT0ibiIpCiNpbWFnZShwcm9wLCBjb2wgPSBjb2xvcnMxKDIwKSwgYXhlcz1GQUxTRSkKYXhpcygxLCBhdD1jKDAsIC40LCAuOCwgMS4yLCAxLjMpLCBsYWJlbHM9bGFicywgdGljayA9IEZBTFNFLCBsaW5lID0gRkFMU0UsIGNleC5heGlzID0gMSwgcG9zID0gLS4xOSwgbGFzPTIpCmF4aXMoMiwgYXQ9cmV2KGMoLTAuMDUsIDAuMDUsIC40LCAuOCwgMS4yKSksIGxhYmVscz1sYWJzLCB0aWNrID0gRkFMU0UsIGxpbmUgPSBGQUxTRSwgY2V4LmF4aXMgPSAxLCBsYXM9MikKbXRleHQoInBlcmNlbnQgb2YgdGltZSB0aGF0IFJGIGlkZW50aWZpZXMgaW5wdXQgbW9kZWwgYXMgZWFjaCBtb2RlbCB0eXBlIiwgc2lkZSA9IDEsIHBhZGogPSAxMCwgY2V4ID0gMSkKbXRleHQoImtub3duIG1vZGVsIHR5cGUgZ2l2ZW4gdG8gcmFuZG9tIGZvcmVzdCIsIHNpZGUgPSAyLCBwYWRqID0gLTEwLCBjZXggPSAxKQoKCgpmb3IoaSBpbiAxOjQpIHsKICBmb3IoaiBpbiA0OjEpIHsKICAgIHhzIDwtIGMoMCwgLjQsIC44LCAxLjIpW2ldCiAgICB5cyA8LSByZXYoYygwLCAuNCwgLjgsIDEuMikpW2pdCiAgICBwb2x5Z29uKHg9Yyh4cy0wLjIsIHhzLTAuMiwgeHMrMC4yLCB4cyswLjIpLCB5PWMoeXMtMC4yLCB5cyswLjIsIHlzKzAuMiwgeXMtMC4yKSwgY29sPWNvbG9yczEoMTAwKVtyb3VuZChhcy5udW1lcmljKGNvbmZ1c2lvbltpLCBqXSksIDEpKzFdKQogICAgaWYoaSA9PSBqKXt0ZXh0KHggPSB4cywgeSA9IHlzLCBwYXN0ZTAocm91bmQoYXMubnVtZXJpYyhjb25mdXNpb25baSwgal0pLCAyKSwgIiUiKSwgY2V4ID0gMi4yLCBjb2w9ImxpbWVncmVlbiIpfWVsc2V7KHRleHQoeCA9IHhzLCB5ID0geXMsIHBhc3RlMChyb3VuZChhcy5udW1lcmljKGNvbmZ1c2lvbltpLCBqXSksIDIpLCAiJSIpLCBjZXggPSAyLjIsIGNvbD0iYmxhY2siKSl9CiAgfQp9CgpgYGAKCgohW10oY29uZnVzaW9uX21hdHJpeC5wbmcpCgoKCgoKYGBge3J9CgojY29sbmFtZXMocmVzX2FjdW0pCgpsb25nIDwtIGxlbmd0aChDb25mdXNpb25fMDEwMV9tZWFuWywxXSkKQ29uZnVzaW9uX3N1bV8wMSA8LSBhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgMjU6NTRdLCBieSA9IGxpc3QoKHJlc19hY3VtWywgMV0pKSwgRlVOID0gbWVhbikKQ29uZnVzaW9uX3N1bV8wMiA8LSBhZ2dyZWdhdGUoeCA9IHJlc19hY3VtWywgOToxMl0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQpDb25mdXNpb25fc3VtXzAzIDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAxMzoxNl0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQpDb25mdXNpb25fc3VtXzA0IDwtIGFnZ3JlZ2F0ZSh4ID0gcmVzX2FjdW1bLCAxNzoyMF0sIGJ5ID0gbGlzdCgocmVzX2FjdW1bLCAxXSkpLCBGVU4gPSBtZWFuKQoKCgoKIyBWYXJpYWJsZXMgaW1wb3J0YW5jZQoKaW1wIDwtIGltcG9ydGFuY2UoZml0KQppbXAgPC0gYXBwbHkoaW1wLCAyLCBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkvKG1heCh4KSAtIG1pbih4KSkpCmltcCA8LSBpbXBbc29ydChpbXBbLCA1XSwgaW5kZXgucmV0dXJuID0gVFJVRSwgZGVjcmVhc2luZyA9IFRSVUUpJGl4LCBdCgphcy5jaGFyYWN0ZXIocmVwbGFjZVssIDZdKQpsb2FkKGFzLmNoYXJhY3RlcihyZXBsYWNlWzkwLCA2XSkpCmltcCA8LSBpbXBvcnRhbmNlKGZpdCkKCm5hbWVzIDwtIHJvd25hbWVzKGltcCkKbmFtZXNbbmFtZXMgPT0gInNwYXRpYWwudGVzdHMuZm9yYSJdIDwtICJTcGFjZSBGIgpuYW1lc1tuYW1lcyA9PSAic3BhdGlhbC50ZXN0cy5kb20iXSA8LSAiU3BhY2UgRCIKbmFtZXNbbmFtZXMgPT0gInNwcmF0ZSJdIDwtICJTcChyYXRpbykiCm5hbWVzW25hbWVzID09ICJ0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yIl0gPC0gIlRSKDEtMikiCm5hbWVzW25hbWVzID09ICJ0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xIl0gPC0gIlRSKDItMSkiCm5hbWVzW25hbWVzID09ICJQaHlsb2dlbmV0aWNfc2lnbmFsIl0gPC0gIlBoeVNpZyhEKSIKbmFtZXNbbmFtZXMgPT0gIkV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3Nfc3VtIl0gPC0gIkVEc3VtIgpuYW1lc1tuYW1lcyA9PSAiUHlsb19kaXZlcnNpdHlfaXNfc3VtX29mX0JMIl0gPC0gIlBEc3VtIgpuYW1lc1tuYW1lcyA9PSAidHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIl0gPC0gIlRSKHJhdGlvKSIKbmFtZXNbbmFtZXMgPT0gImdhbW1hIl0gPC0gIkdhbW1hIgpuYW1lc1tuYW1lcyA9PSAibWVhbl9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIl0gPC0gIk1QSSIKbmFtZXNbbmFtZXMgPT0gImV4dHJhdGUiXSA8LSAiRXh0KHJhdGlvKSIKbmFtZXNbbmFtZXMgPT0gImF2ZXJhZ2VfcGh5bG9nZW5ldGljX2RpdmVyc2l0eV9pc19tZWFuX29mX0JMIl0gPC0gIlBEbWVhbiIKbmFtZXNbbmFtZXMgPT0gImV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24iXSA8LSAiRFIiCm5hbWVzW25hbWVzID09ICJ2YXJpYW5jZV9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIl0gPC0gIlZQSSIKbmFtZXNbbmFtZXMgPT0gIkZfcXVhZHJhdGljX2VudHJvcHlfaXNfc3VtX29mX1BEIl0gPC0gIkYiCm5hbWVzW25hbWVzID09ICJNZWFuX3BhaXJ3aXNlX2Rpc3RhbmNlIl0gPC0gIk1QRCIKbmFtZXNbbmFtZXMgPT0gInZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMIl0gPC0gIlBEdmFyIgpuYW1lc1tuYW1lcyA9PSAidmFyaWFuY2VfcGFpcndpc2VfZGlzdGFuY2UiXSA8LSAiVlBEIgoKCnhfbGVuZ3RoIDwtIGxlbmd0aChsZXZlbHMocmVwbGFjZVssMV0pKQoKIyMjIyMjCiMgbWFrZSBtYXRyaXgKCgoKCgoKCgojIyMjIwojcGxvdCBmcm9tIG1hdHJpeAoKCgoKCgoKCgoKcGRmKGZpbGU9ImhlYXQgbWFwIG9mIHZhcmlhYmxlIGltcG9ydGFuY2UucGRmIiwgd2lkdGg9MTEsIGhlaWdodD04LjUpCgpwYXIobWFyPWMoNCwxMCw0LDEpKQpwbG90KHggPSBzZXEoMSwgeF9sZW5ndGgsIGJ5PTEpLCB5ID0gcmVwKDAsIHhfbGVuZ3RoKSwgdHlwZT0ibiIsIHlsaW09YygwLDIwKSwgeWxhYj0iIiwgeWF4dD0ibiIsIHhheHQ9Im4iLCB4bGFiPSIiLCB4bGltPWMoMSwgeF9sZW5ndGgqMTAwKSkKCmF4aXMoMiwgbGFiZWw9bmFtZXMsIGF0PXNlcSgwLjUsbGVuZ3RoKG5hbWVzKS0uNSksIGxhcz0yKQoKCmZvcihpIGluIDE6bGVuZ3RoKGFzLmNoYXJhY3RlcihyZXBsYWNlWywgNl0pKSl7CgkKCWxvYWQoYXMuY2hhcmFjdGVyKHJlcGxhY2VbaSwgNl0pKQoJaW1wIDwtIGltcG9ydGFuY2UoZml0KQojaW1wIDwtIGFwcGx5KGltcCwgMiwgZnVuY3Rpb24oeCkgKHggLSBtaW4oeCkpLyhtYXgoeCkgLSBtaW4oeCkpKQoJI2kgPC0gMTAKCQp4X3JhbmdlIDwtIGMoaSwgaSwgaSsxLCBpKzEpCQpwZXJjZW50IDwtIGFzLm51bWVyaWMoY2VpbGluZyhpbXBbLDVdICkpCnBlcmNlbnRbd2hpY2gocGVyY2VudCA9PSAwKV0gPC0gTkEKY29sb3JzIDwtIGNtLmNvbG9ycygxMDApW3BlcmNlbnRdCgpmb3IoaiBpbiAwOjE5KXsKCXlfcmFuZ2UgPC0gYyhqLCBqKzEsIGorMSwgaikKcG9seWdvbih4ID0geF9yYW5nZSwgeSA9IHlfcmFuZ2UsIGNvbD0gY29sb3JzW2orMV0sIGJvcmRlcj1OQSkKfQoKfQoKYWJsaW5lKHY9c2VxKDAsMTAwMCwgYnk9MTAwKSkKCmF4aXMoMSwgbGFiZWw9Zm9ybWF0KHVuaXF1ZShyZXBsYWNlWyw3XSksIGZvcm1hdD0iJWQgJWIgJVkiKSwgYXQ9c2VxKDUwLDk1MCwgYnk9MTAwKVsxOmxlbmd0aCh1bmlxdWUocmVwbGFjZVssN10pKV0pCmRldi5vZmYoKQoKYGBgCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKYGBge3IgZXZhbD1GQUxTRX0KaW1wb3J0YW5jZShmaXQpCmBgYAoKCmBgYHtyIGV2YWw9RkFMU0V9CiMgVmFyaWFibGVzIGltcG9ydGFuY2UKCmltcCA8LSBpbXBvcnRhbmNlKGZpdCkKaW1wIDwtIGFwcGx5KGltcCwgMiwgZnVuY3Rpb24oeCkgKHggLSBtaW4oeCkpLyhtYXgoeCkgLSBtaW4oeCkpKQppbXAgPC0gaW1wW3NvcnQoaW1wWywgNV0sIGluZGV4LnJldHVybiA9IFRSVUUsIGRlY3JlYXNpbmcgPSBUUlVFKSRpeCwgXQoKCm5hbWVzIDwtIHJvd25hbWVzKGltcCkKbmFtZXNbbmFtZXMgPT0gInNwYXRpYWwudGVzdHMuZm9yYSJdIDwtICJTcGFjZSBGIgpuYW1lc1tuYW1lcyA9PSAic3BhdGlhbC50ZXN0cy5kb20iXSA8LSAiU3BhY2UgRCIKbmFtZXNbbmFtZXMgPT0gInNwcmF0ZSJdIDwtICJTcChyYXRpbykiCm5hbWVzW25hbWVzID09ICJ0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMV90b18yIl0gPC0gIlRSKDEtMikiCm5hbWVzW25hbWVzID09ICJ0cmFuc2l0aW9uX2Zyb21fdHJhaXRfMl90b18xIl0gPC0gIlRSKDItMSkiCm5hbWVzW25hbWVzID09ICJQaHlsb2dlbmV0aWNfc2lnbmFsIl0gPC0gIlBoeVNpZyhEKSIKbmFtZXNbbmFtZXMgPT0gIkV2b2x1dGlvbmFyeV9kaXN0aW5jdGl2ZW5lc3Nfc3VtIl0gPC0gIkVEc3VtIgpuYW1lc1tuYW1lcyA9PSAiUHlsb19kaXZlcnNpdHlfaXNfc3VtX29mX0JMIl0gPC0gIlBEc3VtIgpuYW1lc1tuYW1lcyA9PSAidHJhbnNpdGlvbl9yYXRlX3JhdGlvXzF0bzJfb3Zlcl8ydG8xIl0gPC0gIlRSKHJhdGlvKSIKbmFtZXNbbmFtZXMgPT0gImdhbW1hIl0gPC0gIkdhbW1hIgpuYW1lc1tuYW1lcyA9PSAibWVhbl9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIl0gPC0gIk1QSSIKbmFtZXNbbmFtZXMgPT0gImV4dHJhdGUiXSA8LSAiRXh0KHJhdGlvKSIKbmFtZXNbbmFtZXMgPT0gImF2ZXJhZ2VfcGh5bG9nZW5ldGljX2RpdmVyc2l0eV9pc19tZWFuX29mX0JMIl0gPC0gIlBEbWVhbiIKbmFtZXNbbmFtZXMgPT0gImV4dGluY3Rpb25fcGVyX3NwZWNpYXRpb24iXSA8LSAiRFIiCm5hbWVzW25hbWVzID09ICJ2YXJpYW5jZV9QaHlsb2dlbmV0aWNfaXNvbGF0aW9uIl0gPC0gIlZQSSIKbmFtZXNbbmFtZXMgPT0gIkZfcXVhZHJhdGljX2VudHJvcHlfaXNfc3VtX29mX1BEIl0gPC0gIkYiCm5hbWVzW25hbWVzID09ICJNZWFuX3BhaXJ3aXNlX2Rpc3RhbmNlIl0gPC0gIk1QRCIKbmFtZXNbbmFtZXMgPT0gInZhcmlhbmNlX1B5bG9fZGl2ZXJzaXR5X2lzX3ZhcmlhbmNlX29mX0JMIl0gPC0gIlBEdmFyIgpuYW1lc1tuYW1lcyA9PSAidmFyaWFuY2VfcGFpcndpc2VfZGlzdGFuY2UiXSA8LSAiVlBEIgoKCnBuZygidmFyX2ltcG9ydF9hbGwucG5nIiwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMjUsIHVuaXQ9ImluIiwgcmVzPTMwMCkKcGFyKG1hciA9IGMoMTAsIDE4LCAxLCAxKSkKcGxvdCh4ID0gcmV2KGltcFssIDVdKSwgeSA9IDE6bnJvdyhpbXApLCB0eXBlID0gImwiLCB5YXh0ID0gIm4iLCAKICAgICB5bGFiID0gIiIsIHhsYWIgPSAiVmFyaWFibGUgSW1wb3J0YW5jZSIsCiAgICAgeGxpbSA9IGMoMCwgMSksIGx3ZCA9IDIsIGNleC5sYWIgPSA0KQpmb3IgKGkgaW4gMTpucm93KGltcCkpIHsKICBhYmxpbmUoaCA9IGksIGx0eSA9IDMsIGNvbCA9ICJncmF5ODAiKQp9CmFibGluZSh2ID0gc2VxKDAsIDEsIDEvMTkpLCBsdHkgPSAzLCBjb2wgPSAiZ3JheTgwIikKCmxpbmVzKHggPSByZXYoaW1wWywgNF0pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJkYXJrZ3JlZW4iLCBsd2QgPSAyKQpsaW5lcyh4ID0gcmV2KGltcFssIDNdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAicmVkIiwgbHdkID0gMikKbGluZXMoeCA9IHJldihpbXBbLCAyXSksIHkgPSAxOm5yb3coaW1wKSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQpsaW5lcyh4ID0gcmV2KGltcFssIDFdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAiZGFya29yYW5nZTEiLCBsd2QgPSAyKQpsaW5lcyh4ID0gcmV2KGltcFssIDVdKSwgeSA9IDE6bnJvdyhpbXApLCBsd2QgPSAzKQoKcG9pbnRzKHggPSByZXYoaW1wWywgNF0pLCB5ID0gMTpucm93KGltcCksIGNvbCA9ICJkYXJrZ3JlZW4iLCBjZXggPSAyKQpwb2ludHMoeCA9IHJldihpbXBbLCAzXSksIHkgPSAxOm5yb3coaW1wKSwgY29sID0gInJlZCIsIGNleCA9IDIpCnBvaW50cyh4ID0gcmV2KGltcFssIDJdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAiYmx1ZSIsIGNleCA9IDIpCnBvaW50cyh4ID0gcmV2KGltcFssIDFdKSwgeSA9IDE6bnJvdyhpbXApLCBjb2wgPSAiZGFya29yYW5nZTEiLCBjZXggPSAyKQpwb2ludHMoeCA9IHJldihpbXBbLCA1XSksIHkgPSAxOm5yb3coaW1wKSwgcGNoID0gMjAsIGNleCA9IDMpCgoKdGV4dCh5ID0gMTpucm93KGltcCksIHggPSBwYXIoInVzciIpWzFdIC0gLjE3LCBsYWJlbHMgPSByZXYobmFtZXMpLAogICAgIHNydCA9IDAsIHBvcyA9IDQsIHhwZCA9IFQsIGNleCA9IDQpCmRldi5vZmYoKQpgYGAKCiFbXSh2YXJfaW1wb3J0X2FsbC5wbmcpCgoKCgpgYGB7ciBldmFsPUZBTFNFfQpwYXIobWZyb3c9YygyLDMpKQoKIyBCb3ggcGxvdHMKYm94cGxvdChzcGF0aWFsLnRlc3RzLmZvcmEgfiBNb2RlbCwgZGF0YSA9IGRhdGEuYW5hbHlzaXMuY29tcDMpCmFibGluZShoID0gYSRzcGF0aWFsLnRlc3RzLmZvcmEsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKYm94cGxvdChzcGF0aWFsLnRlc3RzLmRvbSB+IE1vZGVsLCBkYXRhID0gZGF0YS5hbmFseXNpcy5jb21wMykKYWJsaW5lKGggPSBhJHNwYXRpYWwudGVzdHMuZm9yYSwgY29sID0gInJlZCIsIGx0eSA9IDIpCgpib3hwbG90KGxvZyhzcHJhdGUpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygtMTAsIDEwKSkKYWJsaW5lKGggPSBsb2coYSRzcHJhdGUpLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKCmJveHBsb3QobG9nKGV4dHJhdGUpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygtMTAsIDEwKSkKYWJsaW5lKGggPSBsb2coYSRleHRyYXRlKSwgY29sID0gInJlZCIsIGx0eSA9IDIpCgpib3hwbG90KGxvZyh0cmFuc2l0aW9uX3JhdGVfcmF0aW9fMXRvMl9vdmVyXzJ0bzEpIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzKQphYmxpbmUoaCA9IGxvZyhhJHNwcmF0ZSksIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKYm94cGxvdChQaHlsb2dlbmV0aWNfc2lnbmFsIH4gTW9kZWwsIGRhdGEgPSBkYXRhLmFuYWx5c2lzLmNvbXAzLCB5bGltID0gYygwLCAxKSkKYWJsaW5lKGggPSBhJFBoeWxvZ2VuZXRpY19zaWduYWwsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQoKCmBgYAoKCgpgYGB7ciBldmFsPUZBTFNFfQojYnVpbGQgYSBkYXRhIHRyYWNraW5nIHRhYmxlIHRvIHRyYWNrIHBhcmFtZXRlciBjaGFuZ2VzIHRocm91Z2ggdGltZQoKc3RyKGZpdCkKCnkKCmBgYAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK